/*
 * *****************************************************************************
 *  Copyright (C) 2014-2020 Dennis Sheirer
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 * ****************************************************************************
 */

package io.github.dsheirer.module.decode.ip.cellocator;

import io.github.dsheirer.bits.CorrectedBinaryMessage;

/**
 * Unit (Outbound) data being forwarded over the wireless interface to a central application
 */
public class ForwardedDataMessage extends MCGPPacket
{
    //This field is byte reversed (ie big endian)
    private static final int[] TARGET_UNIT_ID = new int[]{24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22,
            23, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7};
    private static final int[] COMMAND_NUMERATOR = new int[]{48, 49, 50, 51, 52, 53, 54, 55};
    private static final int[] FORWARDED_MESSAGE_NUMBER = new int[]{88, 89, 90, 91, 92, 93, 94, 95};
    private static final int[] FRAGMENT_CONTROL = new int[]{96, 97, 98, 99, 100, 101, 102, 103};
    private static final int[] PAYLOAD_LENGTH = new int[]{112, 113, 114, 115, 116, 117, 118, 119, 104, 105, 106, 107,
            108, 109, 110, 111};
    private static final int PAYLOAD_START = 120;

    private CellocatorRadioIdentifier mTargetRadioId;
    private FragmentControl mFragmentControl;

    /**
     * Constructs a parser for a header contained within a binary message starting at the offset.
     *
     * @param header for this message
     * @param message containing the packet
     * @param offset to the packet within the message
     */
    public ForwardedDataMessage(MCGPHeader header, CorrectedBinaryMessage message, int offset)
    {
        super(header, message, offset);
    }

    /**
     * Target radio ID to receive the forwarded data
     */
    public CellocatorRadioIdentifier getRadioId()
    {
        if(mTargetRadioId == null)
        {
            mTargetRadioId = CellocatorRadioIdentifier.createTo(getMessage().getInt(TARGET_UNIT_ID, getOffset()));
        }

        return mTargetRadioId;
    }

    /**
     * Message fragment control structure
     */
    public FragmentControl getFragmentControl()
    {
        if(mFragmentControl == null)
        {
            mFragmentControl = new FragmentControl(getMessage().getInt(FRAGMENT_CONTROL, getOffset()));
        }

        return mFragmentControl;
    }

    /**
     * This message number
     */
    public int getMessageNumerator()
    {
        return getMessage().getInt(COMMAND_NUMERATOR, getOffset());
    }

    /**
     * Message number for the forwarded message
     */
    public int getForwardedMessageNumerator()
    {
        return getMessage().getInt(FORWARDED_MESSAGE_NUMBER, getOffset());
    }

    /**
     * Length of the payload in bytes
     */
    private int getPayloadLength()
    {
        return getMessage().getInt(PAYLOAD_LENGTH, getOffset());
    }

    /**
     * Hexadecimal representation of the payload data.
     */
    public String getPayloadData()
    {
        int payloadEnd = PAYLOAD_START + (getPayloadLength() * 8);
        return getMessage().get(PAYLOAD_START, payloadEnd).toHexString();
    }

    @Override
    public String toString()
    {
        StringBuilder sb = new StringBuilder();
        sb.append("CELLOCATOR TO RADIO:");
        sb.append(getRadioId());
        sb.append(" MESSAGE NUMBER:").append(getMessageNumerator());

        if(getHeader().getMessageType() == MCGPMessageType.OUTBOUND_FORWARDED_REALTIME_DATA)
        {
            sb.append(" FORWARDED SERIAL PORT DATA");
        }
        else
        {
            sb.append(" FORWARDED LOGGED DATA");
        }

        sb.append(" MESSAGE NUMBER:").append(getForwardedMessageNumerator());
        sb.append(" ").append(getFragmentControl());

        return sb.toString();
    }
}
